
The aggregation approach implemented in TrajectoryCollectionAggregator is based on Andrienko, N., & Andrienko, G. (2011). Spatial generalization and aggregation of massive movement data. IEEE Transactions on visualization and computer graphics, 17(2), 205-219. and consists of the following main steps:
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
import shapely as shp
import hvplot.pandas
import matplotlib.pyplot as plt
from geopandas import GeoDataFrame, read_file
from shapely.geometry import Point, LineString, Polygon
from datetime import datetime, timedelta
from holoviews import opts, dim
import warnings
warnings.filterwarnings('ignore')
plot_defaults = {'linewidth':5, 'capstyle':'round', 'figsize':(9,3), 'legend':True}
opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=500, frame_height=400))
mpd.show_versions()
MovingPandas 0.10.rc1 SYSTEM INFO ----------- python : 3.9.13 | packaged by conda-forge | (main, May 27 2022, 16:50:36) [MSC v.1929 64 bit (AMD64)] executable : H:\miniconda3\envs\mpd-ex\python.exe machine : Windows-10-10.0.19043-SP0 GEOS, GDAL, PROJ INFO --------------------- GEOS : None GEOS lib : None GDAL : 3.5.0 GDAL data dir: None PROJ : 9.0.0 PROJ data dir: H:\miniconda3\pkgs\proj-9.0.0-h1cfcee9_1\Library\share\proj PYTHON DEPENDENCIES ------------------- geopandas : 0.10.2 pandas : 1.4.2 fiona : 1.8.21 numpy : 1.22.4 shapely : 1.8.2 rtree : 1.0.0 pyproj : 3.3.1 matplotlib : 3.5.2 mapclassify: 2.4.3 geopy : 2.2.0 holoviews : 1.14.9 hvplot : 0.8.0 geoviews : 1.9.5 stonesoup : 0.1b9
gdf = read_file('../data/geolife_small.gpkg')
traj_collection = mpd.TrajectoryCollection(gdf, 'trajectory_id', t='t')
traj_collection.hvplot(line_width=7.0, tiles='StamenTonerBackground')
help(mpd.TrajectoryCollectionAggregator)
Help on class TrajectoryCollectionAggregator in module movingpandas.trajectory_aggregator: class TrajectoryCollectionAggregator(builtins.object) | TrajectoryCollectionAggregator(traj_collection, max_distance, min_distance, min_stop_duration, min_angle=45) | | Methods defined here: | | __init__(self, traj_collection, max_distance, min_distance, min_stop_duration, min_angle=45) | Aggregates trajectories by extracting significant points, | clustering those points, and extracting flows between clusters. | | Parameters | ---------- | traj_collection : TrajectoryCollection | TrajectoryCollection to be aggregated | max_distance : float | Maximum distance between significant points (distance is | calculated in CRS units, except if the CRS is geographic, e.g. | EPSG:4326 WGS84, then distance is calculated in meters) | min_distance : float | Minimum distance between significant points | min_stop_duration : integer | Minimum duration required for stop detection (in seconds) | min_angle : float | Minimum angle for significant point extraction | | References | ---------- | * Andrienko, N., & Andrienko, G. (2011). Spatial generalization and | aggregation of massive movement data. IEEE Transactions on | visualization and computer graphics, 17(2), 205-219. | | get_clusters_gdf(self) | Return the extracted cluster centroids | | Returns | ------- | GeoDataFrame | Cluster centroids, incl. the number of clustered significant | points (n). | | get_flows_gdf(self) | Return the extracted flows | | Returns | ------- | GeoDataFrame | Flow lines, incl. the number of trajectories summarized in the | flow (weight). | | get_significant_points_gdf(self) | Return the extracted significant points | | Returns | ------- | GeoDataFrame | Significant points | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)
Generalizing the trip trajectories significantly speeds up the following aggregation step.
generalized = mpd.MinDistanceGeneralizer(traj_collection).generalize(tolerance=100)
aggregator = mpd.TrajectoryCollectionAggregator(generalized, max_distance=1000, min_distance=100, min_stop_duration=timedelta(minutes=5))
pts = aggregator.get_significant_points_gdf()
clusters = aggregator.get_clusters_gdf()
( pts.hvplot(geo=True, tiles='StamenTonerBackground') *
clusters.hvplot(geo=True, color='red' ) )
flows = aggregator.get_flows_gdf()
( flows.hvplot(geo=True, hover_cols=['weight'], line_width=dim('weight')*7, color='#1f77b3', tiles='StamenTonerBackground') *
clusters.hvplot(geo=True, color='red', size=dim('n') ) )